<?php declare(strict_types=1);


namespace Tool\Contract;

use Closure;
use Generator;
use ReflectionException;
use Swoft\Bean\Exception\ContainerException;
use Swoft\Db\Exception\DbException;
use Swoft\Db\Query\Expression;
use Throwable;
use Communication\Contract\ITxDatabase;
use Tool\Pool;
use Tool\Database;
use Swoft\Db\Query\Processor\Processor;

/**
 * Class ConnectionInterface
 *
 * @since 2.0
 */
interface IConnection extends ITxDatabase
{
    /**
     * Get a new raw query expression.
     *
     * @param mixed $value
     *
     * @return Expression
     */
    public function raw($value): Expression;

    /**
     * Run a select statement and return a single result.
     *
     * @param string $query
     * @param array  $bindings
     * @param bool   $useReadPdo
     *
     * @return mixed
     */
    public function selectOne($query, $bindings = [], $useReadPdo = true);

    /**
     * Run a select statement against the database.
     *
     * @param string $query
     * @param array  $bindings
     * @param bool   $useReadPdo
     *
     * @return array
     */
    public function select(string $query, array $bindings = [], bool $useReadPdo = true): array;

    /**
     * @param string $dbname
     *
     * @return static
     */
    public function db(string $dbname);

    /**
     * Run a select statement against the database and returns a generator.
     *
     * @param string $query
     * @param array  $bindings
     * @param bool   $useReadPdo
     *
     * @return Generator
     */
    public function cursor(string $query, array $bindings = [], bool $useReadPdo = true): Generator;

    /**
     * Run an insert statement against the database.
     *
     * @param string $query
     * @param array  $bindings
     *
     * @return bool
     */
    public function insert(string $query, array $bindings = []): bool;

    /**
     * Run an insert statement against the database.
     *
     * @param string $query
     * @param array  $bindings
     * @param string $sequence
     *
     * @return string
     * @throws ContainerException
     * @throws DbException
     * @throws ReflectionException
     */
    public function insertGetId(string $query, array $bindings = [], string $sequence = null): string;

    /**
     * Run an update statement against the database.
     *
     * @param string $query
     * @param array  $bindings
     *
     * @return int
     */
    public function update(string $query, array $bindings = []): int;

    /**
     * Run a delete statement against the database.
     *
     * @param string $query
     * @param array  $bindings
     *
     * @return int
     */
    public function delete(string $query, array $bindings = []): int;

    /**
     * Execute an SQL statement and return the boolean result.
     *
     * @param string $query
     * @param array  $bindings
     *
     * @return bool
     */
    public function statement(string $query, array $bindings = []): bool;

    /**
     * Run an SQL statement and get the number of rows affected.
     *
     * @param string $query
     * @param array  $bindings
     *
     * @return int
     */
    public function affectingStatement(string $query, array $bindings = []): int;

    /**
     * Run a raw, unprepared query against the PDO connection.
     *
     * @param string $query
     *
     * @return bool
     */
    public function unprepared(string $query): bool;

    /**
     * Prepare the query bindings for execution.
     *
     * @param array $bindings
     *
     * @return array
     */
    public function prepareBindings(array $bindings): array;

    /**
     * Execute a Closure within a transaction.
     *
     * @param Closure $callback
     * @param int     $attempts
     *
     * @return mixed
     *
     * @throws Throwable
     */
    public function transaction(Closure $callback, $attempts = 1);


    /**
     * @return bool
     */
    public function inTransaction(): bool;

    /**
     * Force rollback the active database transaction.
     *
     * @param int|null $toLevel
     */
    public function forceRollBack(int $toLevel = null): void;

    /**
     * Get the number of active transactions.
     *
     * @return void
     */
    public function transactionLevel(): void;

    /**
     * Execute the given callback in "dry run" mode.
     *
     * @param Closure $callback
     *
     * @return array
     */
    public function pretend(Closure $callback): array;
    
    /**
     * Returns the raw SQL by inserting parameter values into the corresponding placeholders in [[sql]].
     * Note that the return value of this method should mainly be used for logging purpose.
     * It is likely that this method returns an invalid SQL due to improper replacement of parameter placeholders.
     *
     * @param string $sql
     * @param array  $bindings
     *
     * @return string the raw SQL with parameter values inserted into the corresponding placeholders in [[sql]].
     */
    public function getRawSql(string $sql, array $bindings);
    
    /**
     * Replace constructor
     *
     * @param Pool     $pool
     * @param Database $database
     *
     */
    public function initialize(Pool $pool, Database $database): void;
    
    
    /**
     * Get the query post processor used by the connection.
     *
     * @return Processor
     */
    public function getPostProcessor() : Processor;
    
    
    /**
     * Set the query post processor to the default implementation.
     *
     * @return void
     */
    public function useDefaultPostProcessor(): void;
    
    /**
     * Set the query post processor used by the connection.
     *
     * @param Processor $processor
     *
     * @return $this
     */
    public function setPostProcessor(Processor $processor);
}
